package com.zelix.analy;

import com.arthas.client.ArthasClient;
import com.arthas.client.ArthasTool;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.tree.*;

import java.io.IOException;
import java.util.Enumeration;
import java.util.List;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.zip.ZipEntry;

public class analyString {
    private static String classLoader = null;

    public static void main(String[] args) throws IOException {

        JarFile jarFile = null;
        try {
            jarFile = new JarFile("./file/lsrv-floating.jar");
        } catch (IOException e) {
            e.printStackTrace();
        }

        ArthasClient client = ArthasTool.getClient("192.168.81.128", 3658);

        if (jarFile == null || client == null) {
            return;
        }

        //获取类所在的classloader,idea中的一些方法不加classloader去运行,可能找不到类
        //一个jar包基本有同一个ClassLoader,找一个存在的类,这样就可以解析所有类了,而不是已经加载的
        classLoader = ArthasTool.getClassLoader(client, "com/jetbrains/ls/floating/g");
        if (classLoader == null) {
            System.out.println("类还未加载,请点击相应功能触发其加载.");
            return;
        }

        String rule = "com/jetbrains/ls/floating/dashboard/Register";
        rule = "com/jetbrains/ls/floating/g";
        rule = "com/jetbrains/ls/floating/dashboard/Dashboard";
        rule = "com/jetbrains/ls/floating/upstream/b";
        rule = "com";
        //rule = "jetprofile";
        rule = "com/jetbrains/ls/floating/a/a";
        //rule = "com/jetbrains/ls/floating/h";

        Enumeration<JarEntry> entries = jarFile.entries();
        while (entries.hasMoreElements()) {
            JarEntry entry = entries.nextElement();
            if (entry.getName().endsWith(".class")) {//只分析class文件
                //去除文件名后缀 ".class"
                analy(client, jarFile, entry.getName().substring(0, entry.getName().length() - 6));
            }
        }

        client.disconnect();
    }

    public static void analy(ArthasClient client, JarFile jarFile, String cls) throws IOException {

        //字符串加密的ognl表示方式
        String stringMethod = null;
        ZipEntry entry = jarFile.getEntry(cls + ".class");

        if (entry != null) {
            ClassReader cr = new ClassReader(jarFile.getInputStream(entry));
            ClassNode cn = new ClassNode();
            cr.accept(cn, 0);

            List<MethodNode> methods = cn.methods;

            //查找符合的方法并初始化解密方法
            for (MethodNode methodNode : methods) {
                if (methodNode.desc.equals("(II)Ljava/lang/String;")) {
                    stringMethod = "@" + cls.replaceAll("/", ".") + "@" + methodNode.name;
                }
            }

            System.out.println("************" + cls + "************");
            //类的注解
            if (cn.visibleAnnotations != null && cn.visibleAnnotations.size() > 0) {
                cn.visibleAnnotations.stream().forEach(annotationNode -> {
                    //获取get或者post类型注解
                    if (annotationNode.desc.equals("Lkara/Get;") || annotationNode.desc.equals("Lkara/Post;")) {
                        System.out.println("HTTP映射路径:" + annotationNode.desc + "->" + annotationNode.values);
                    }
                });
            }

            //遍历方法
            for (MethodNode methodNode : methods) {
                System.out.println("------------" + methodNode.name + ":" + methodNode.desc + "------------");
                InsnList insnList = methodNode.instructions;
                //遍历指令
                for (int i = 0; i < insnList.size(); i++) {
                    //查找MethodInsnNode指令
                    if (insnList.get(i) instanceof MethodInsnNode) {
                        MethodInsnNode methodInsnNode = (MethodInsnNode) insnList.get(i);
                        //查找这个描述的方法
                        if (methodInsnNode.desc.equals("(II)Ljava/lang/String;")) {
                            //所有者是本类
                            if (methodInsnNode.owner.equals(cls)) {
                                /**
                                 * 只解析如下格式
                                 * SIPUSH -15502
                                 * SIPUSH -11843
                                 * INVOKESTATIC com/jetbrains/ls/floating/dashboard/Register$a.a(II)Ljava/lang/String;
                                 */
                                if (insnList.get(i - 1) instanceof IntInsnNode && insnList.get(i - 2) instanceof IntInsnNode) {
                                    IntInsnNode intNode1 = (IntInsnNode) insnList.get(i - 2);
                                    IntInsnNode intNode2 = (IntInsnNode) insnList.get(i - 1);
                                    String rtn = client.sendCommand("ognl '" + stringMethod + "(" + intNode1.operand + "," + intNode2.operand + ")' -c " + classLoader);
                                    System.out.println("(" + intNode1.operand + "," + intNode2.operand + "):" + ArthasTool.removeStringLebal(rtn));
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}
